package com.xiyu.service.service.mailbox;

import com.xiyu.service.service.system.user.UserService;
import com.xiyu.service.vo.mailbox.mailboxAccount.MailboxAccountGetTopAccountOutput;
import com.xiyu.service.convert.mailbox.MailboxAccountConvert;
import com.xiyu.service.enums.mailbox.folder.MailboxFolderClassEnum;
import com.xiyu.service.enums.mailbox.folder.MailboxFolderTypeEnum;
import com.xiyu.service.framework.postOffice.factory.PostOfficeFactory;
import com.xiyu.service.framework.postOffice.service.PostOfficeService;
import com.xiyu.service.framework.web.web.core.pojo.PageResult;
import com.xiyu.service.model.mailbox.account.MailboxAccount;
import com.xiyu.service.model.mailbox.account.MailboxAccountDraft;
import com.xiyu.service.model.mailbox.folder.MailboxFolder;
import com.xiyu.service.model.mailbox.folder.MailboxFolderDraft;
import com.xiyu.service.model.mailbox.signature.MailboxAccountSignature;
import com.xiyu.service.model.mailbox.signature.MailboxAccountSignatureDraft;
import com.xiyu.service.repository.mailbox.account.MailboxAccountRepository;
import com.xiyu.service.repository.mailbox.folder.MailboxFolderRepository;
import com.xiyu.service.repository.mailbox.signature.MailboxAccountSignatureRepository;
import com.xiyu.service.util.entity.EntityUtils;
import com.xiyu.service.vo.mailbox.mailboxAccount.*;
import org.babyfish.jimmer.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;
import java.util.List;
import java.util.Optional;

import static com.xiyu.service.errorCode.mailbox.MailErrorCode.MAILBOX_ROOT_FOLDER_NOT_EXIST;
import static com.xiyu.service.errorCode.mailbox.MailboxAccountErrorCode.MAILBOX_ACCOUNT_EXIST;
import static com.xiyu.service.errorCode.mailbox.MailboxAccountErrorCode.MAILBOX_ACCOUNT_NOT_EXIST;
import static com.xiyu.service.framework.exception.util.ServiceExceptionUtil.exception;
import static com.xiyu.service.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;

/**
 * 邮箱账号 Service 实现类
 */
@Service
@Validated
public class MailboxAccountServiceImpl implements MailboxAccountService {

    @Resource
    private MailboxAccountRepository mailboxAccountRepository;

    @Resource
    private PostOfficeFactory postOfficeFactory;

    @Resource
    private MailboxFolderRepository mailboxFolderRepository;

    @Resource
    private MailboxAccountSignatureRepository mailboxAccountSignatureRepository;

    @Resource
    private UserService userService;

    @Override
    public PageResult<MailboxAccountPageQueryOutput> pageQuery(MailboxAccountPageQueryInput inputVO) {
        List<Long> ownerUserIds = userService.getOwnerUserIds(getLoginUserId());
        Page<MailboxAccount> pageMailboxAccount = mailboxAccountRepository.pageQuery(inputVO, ownerUserIds);
        List<MailboxAccountPageQueryOutput> listMailboxAccount = MailboxAccountConvert.INSTANCE.pageQueryOutputConvert(pageMailboxAccount.getRows());
        return new PageResult<>(listMailboxAccount, pageMailboxAccount.getTotalRowCount());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(MailboxAccountCreateInput inputVO) {
        Optional<MailboxAccount> optionalDupAccount = mailboxAccountRepository.findFirstByMailboxAccount(inputVO.getMailboxAccount());
        if(optionalDupAccount.isPresent()){
            throw exception(MAILBOX_ACCOUNT_EXIST);
        }

        MailboxAccount newMailboxAccount = MailboxAccountConvert.INSTANCE.createInputConvert(inputVO);
        newMailboxAccount = MailboxAccountDraft.$.produce(newMailboxAccount, draft -> draft.setShowName(StringUtils.hasText(draft.showName()) ?  draft.showName():draft.mailboxAccount())
                .setSendName(StringUtils.hasText(draft.sendName()) ? draft.sendName() : draft.mailboxAccount()));
        newMailboxAccount = mailboxAccountRepository.insert(newMailboxAccount);

        MailboxAccount finalNewMailboxAccount = newMailboxAccount;
        MailboxAccountSignature newSignature = MailboxAccountSignatureDraft.$.produce(draft -> draft.setAccountId(finalNewMailboxAccount.id()));
        mailboxAccountSignatureRepository.insert(newSignature);

        PostOfficeService postOfficeService = postOfficeFactory.getInstance(newMailboxAccount.id());
        postOfficeService.createAccount();
        return newMailboxAccount.id();

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(MailboxAccountUpdateInput inputVO) {
        Optional<MailboxAccount> optionalOldMailboxAccount = mailboxAccountRepository.findById(inputVO.getId());
        if(optionalOldMailboxAccount.isEmpty()){
            throw exception(MAILBOX_ACCOUNT_NOT_EXIST);
        }
        MailboxAccount updateMailboxAccount = MailboxAccountConvert.INSTANCE.updateInputConvert(inputVO);
        updateMailboxAccount = MailboxAccountDraft.$.produce(updateMailboxAccount, draft -> draft.setShowName(StringUtils.hasText(draft.showName()) ?  draft.showName():draft.mailboxAccount())
                .setSendName(StringUtils.hasText(draft.sendName()) ? draft.sendName() : draft.mailboxAccount()));
        if (!EntityUtils.isEquals(optionalOldMailboxAccount.get(), updateMailboxAccount))
            mailboxAccountRepository.update(updateMailboxAccount);

        // 更新根文件夹
        List<MailboxFolder> optionalRootFolder = mailboxFolderRepository.findByAccountIdAndFolderTypeAndFolderClass(updateMailboxAccount.id(), MailboxFolderTypeEnum.ACCOUNT.getValue(), MailboxFolderClassEnum.ACCOUNT.getValue());
        if(optionalRootFolder.size() == 0)
            throw exception(MAILBOX_ROOT_FOLDER_NOT_EXIST);
        MailboxAccount finalUpdateMailboxAccount = updateMailboxAccount;
        MailboxFolder updateRootFolder = MailboxFolderDraft.$.produce(optionalRootFolder.get(0), draft -> draft.setName(finalUpdateMailboxAccount.showName()));
        mailboxFolderRepository.update(updateRootFolder);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleted(Long id) {
        Optional<MailboxAccount> optionMailboxAccount = mailboxAccountRepository.findById(id);
        if(optionMailboxAccount.isEmpty()){
            throw exception(MAILBOX_ACCOUNT_NOT_EXIST);
        }
        mailboxAccountRepository.deleteById(optionMailboxAccount.get().id());
        return true;
    }

    @Override
    public MailboxAccountSingleGetOutput singleGet(Long id) {
        Optional<MailboxAccount> optionMailboxAccount = mailboxAccountRepository.findById(id);
        if(optionMailboxAccount.isEmpty()){
            throw exception(MAILBOX_ACCOUNT_NOT_EXIST);
        }
        return MailboxAccountConvert.INSTANCE.singleGetOutputConvert(optionMailboxAccount.get());

    }

    @Override
    public List<MailboxAccountGetTopAccountOutput> getTopAccount(Long userId) {
        List<MailboxAccount> mailboxAccounts = mailboxAccountRepository.getTopAccount(userId);
        return MailboxAccountConvert.INSTANCE.getTopAccountOutputConvent(mailboxAccounts);
    }

}
